import requests
from concurrent.futures import ThreadPoolExecutor
from sqlalchemy.exc import OperationalError
from sqlalchemy import func
from urllib.parse import urlencode
import json
import math
import time
import os
from logger import singer_logger, song_logger, create_logger
from models.tables import SingerModel, MusicModel
from models import db
import config
from requests import urllib3
urllib3.disable_warnings()


class SongUrlSpider(object):
    def __init__(self, start, end):
        self.thread_pool = ThreadPoolExecutor(max_workers=10)
        self.start = start
        self.end = end
        self.logger = create_logger('song_url--' + str(start) + '---' + str(end))

    def res_runnable(self, music):
        self.logger.info('start song url id=' + str(music.id))
        song_mid = music.song_mid
        callback_key = 'getplaysongvkey725539600059133'
        url = "https://u.y.qq.com/cgi-bin/musicu.fcg?"
        params = {
            "g_tk": 5381,
            "loginUin": 0,
            "hostUin": 0,
            "format": "json",
            "inCharset": "utf8",
            "outCharset": "utf8",
            "notice": 0,
            "platform": 'yqq',
            "needNewCode": 0,
            "callback": callback_key,
            "jsonpCallback": callback_key,
            "data": json.dumps({
                "req": {"module": "CDN.SrfCdnDispatchServer", "method": "GetCdnDispatch",
                        "param": {"guid": "6501846271", "calltype": 0, "userip": ""}},
                "req_0": {
                    "module": "vkey.GetVkeyServer",
                    "method": "CgiGetVkey",
                    "param": {
                        "guid": "6501846271",
                        "songmid": [song_mid],
                        "songtype": [0],
                        "uin": "0",
                        "loginflag": 1,
                        "platform": "20"
                    }
                },
                "comm": {
                    "uin": 0,
                    "format": "json",
                    "ct": 20,
                    "cv": 0
                }
            })
        }
        params_str = urlencode(params)
        url += params_str
        url = url.replace('+', '')
        song_url = []
        sip = []
        try:
            resp = requests.get(url=url, verify=False)
            resp_json_text = resp.text.replace(callback_key + '(', '')
            resp_json_text = resp_json_text[:-1]
            resp_json = json.loads(resp_json_text)
            if resp_json.get('code', None) == 0:
                song_url = resp_json.get('req_0', None).get('data', None).get('midurlinfo', [])
                song_url = [_.get('purl', None) for _ in song_url]
                sip = resp_json.get('req', None).get('data', None).get('sip', [])
        except Exception as e:
            print('Exception get_song_key')
            resp_json = dict()
            self.logger.error(str(e))
        # print('resp_json', resp_json)
        real_url = ''
        if len(song_url) > 0 and len(sip) > 0 and song_url[0] != '' and sip[0] != '':
            real_url = sip[0] + song_url[0]
        self.logger.info('end song url id=' + str(music.id))
        return {
            'id': music.id,
            'real_url': real_url
        }

    def run_single(self, row_id):
        music = db.query(MusicModel).filter_by(id=row_id).one()
        if music.state == 1:
            future = self.thread_pool.submit(self.res_runnable, music)
            future.add_done_callback(self.save_db)

    def run(self):
        for _ in range(self.start, self.end + 1):
            self.run_single(_)

    @staticmethod
    def save_db(url_future):
        try:
            data = url_future.result()
            music = db.query(MusicModel).filter_by(id=data.get('id')).one()
            music.song_url = data.get('real_url', '')
            db.commit()
        except Exception as e:
            print('Run crawl url future thread error. ' + str(e))
